//-------------------------------------------------
//  Title: control.v
//  Module: control
//  Function: Control Signal Generator for MIPS uP
//  Coder: Mitchell Kline
//  Date Created: Apr 1, 2007
//-------------------------------------------------


//-------------OpCode Definitions-------------
`define RTYPE 6'd0
`define ADDI 6'd8
`define ADDIU 6'd9
`define ANDI 6'd12
`define ORI 6'd13
`define LW 6'd35
`define SW 6'd43
`define LUI 6'd15
`define BEQ 6'd4
`define BNE 6'd5
`define SLTI 6'd10
`define SLTIU 6'd11
`define XORI 6'd14
`define BLEZ 6'd6
`define BGTZ 6'd7
`define J 6'd2
`define JAL 6'd3

module control(
  RegWrite,  // When writing a value into the registers
  ALUSrc,    // Control the second operand to the ALU
  ALUOp,  // Select the correct operation for the ALU
  MemWrite,  // When writing to the memory
  MemRead,   // When reading from the memory
  MemtoReg,   // select the data to be written to the registers
  Branch,
  RegDest,
  Jump,
  Signed,  // indicates immediate needs to be sign extended
  IW  // the incoming instruction
  );

//-----------------Port Definitions--------------------

  input [31:0] IW;

  output RegWrite, ALUSrc, MemWrite, MemRead, MemtoReg, Branch, RegDest, Jump, Signed;
  output [3:0] ALUOp;

  reg RegWrite, ALUSrc, MemWrite, MemRead, MemtoReg, Branch, RegDest, Jump, Signed;
  reg [3:0] ALUOp;

//-----------------Code Starts Here------------------------

  always @ (IW)  begin

    case (IW[31:26])  // decide what to do based on the opcode

      `RTYPE: begin
         {RegDest,MemtoReg,MemRead,MemWrite,Branch,Signed}=6'b100000;

         case (IW[5:0])  // decide the specific RTYPE instruction  
           6'd32:  begin  ALUOp = `ADD;  ALUSrc = 1'b0;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd34:  begin  ALUOp = `SUB;  ALUSrc = 1'b0;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd33:  begin  ALUOp = `ADDU; ALUSrc = 1'b0;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd35:  begin  ALUOp = `SUBU; ALUSrc = 1'b0;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd36:  begin  ALUOp = `AND;  ALUSrc = 1'b0;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd37:  begin  ALUOp = `OR;   ALUSrc = 1'b0;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd38:  begin  ALUOp = `XOR;  ALUSrc = 1'b0;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd0:   begin  ALUOp = `SLL;  ALUSrc = 1'b1;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd2:   begin  ALUOp = `SRL;  ALUSrc = 1'b1;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd3:   begin  ALUOp = `SRA;  ALUSrc = 1'b1;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd42:  begin  ALUOp = `SLT;  ALUSrc = 1'b0;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd43:  begin  ALUOp = `SLTU; ALUSrc = 1'b0;  Jump = 1'b0;  RegWrite = 1'b1;  end
           6'd8:   begin  ALUOp = `NOP;  ALUSrc = 1'b1;  Jump = 1'b1;  RegWrite = 1'b0;  end
             // ALUSrc is used to indicate that the J instruction is in fact JR
             // This is possible because no jump instruction relies on ALUSrc
             // Note that RegWrite must be 0 so that the old $ra is not erased
           default: begin ALUOp = `NOP;  ALUSrc = 1'b0;  Jump = 1'b0;  RegWrite = 1'b0;  end
         endcase
      end

      `LW: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b011110000; 
         ALUOp = `ADDU;
      end

      `SW: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b010001000; 
         ALUOp = `ADDU;
      end

      `BEQ: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b000000101; 
         ALUOp = `SUB;
      end

      `BNE: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b000000101; 
         ALUOp = `SZNE;
      end

      `BLEZ: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b000000101; 
         ALUOp = `SZLT;
      end

      `BGTZ: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b000000101; 
         ALUOp = `SZGT;
      end

      `ADDI: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b010100001;
         ALUOp = `ADD;
      end

      `ADDIU: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b010100000;
         ALUOp = `ADDU;
      end

      `ANDI: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b010100000;
         ALUOp = `AND;
      end 

      `ORI: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b010100000;
         ALUOp = `OR;
      end

      `LUI: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b010100000;
         ALUOp = `OR;
      end

      `SLTI: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b010100001;
         ALUOp = `SLT;
      end

      `SLTIU: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b010100000;
         ALUOp = `SLTU;
      end

      `XORI: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b010100000;
         ALUOp = `XOR;
      end

      `J:  begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b000000010;
         ALUOp = `NOP;
      end

     `JAL: begin
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b000100010;
         ALUOp = `NOP;
     end

      default:  begin // illegal instruction
         {RegDest,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,Jump,Signed}=9'b000000000;
         ALUOp = `NOP;
      end
    endcase
  end

endmodule
